require "window.rb"
require "framework.rb"
require "fileutils.rb"
require "dataparse.rb"

#loads game graphics and draws the game map
class Environment 
  class Map
    def Map.loadMaterials
      terrain=ObjectScript::ObjectClass.new("terrain")
      terrain.addStringProperty("name")
      terrain.addStringProperty("image",false)
      terrain.addArrayProperty("animation",4,4,:string,false)
      terrain.addArrayProperty("script_event",2,2,:string,true,true)
      building=ObjectScript::ObjectClass.new("building")
      building.addStringProperty("name")
      building.addStringProperty("image",false)
      building.addArrayProperty("animation",4,4,:string,false)
      building.addArrayProperty("script_event",2,2,:string,true,true)
      building.addArrayProperty("child",3,3,:string,true,true)
      terrain=ObjectScript.new("data/materials/terrain.obj",terrain).run
      building=ObjectScript.new("data/materials/buildings.obj",building).run
      building.each { |item|
        raise unless item.hasProperty?("name")
        raise unless item.hasProperty?("image") or item.hasProperty?("animation")
       # p item
        if item.hasProperty?("image")
          #MapImage.new(subVars(item["name"]),item["src"])
        else
          #MapImage.new(item[name],item[src]
        end
=begin
        if building.hasProperty?("name")
          
        elsif
          
        else
          
        end
=end
      }
    end
    
    def Map.loadProperties

    end
  
    def Map.loadMaterialsOLD
      #mapobject materials
      DataFile.new(Material::Root).each(6) {|args|
        if args!=false
          if args[3].upcase=="TERRAIN"
            type=Material::Terrain          
          elsif args[3].upcase=="ITEM"
            type=Material::Item
          elsif args[3].upcase=="BUILDING"
            type=Material::Building
          else
            type=Material::Terrain
            $flog.error("Environment::Load") {"Script Parser: Bad format for \'type\' attribute."}   
            $flog.warn("Environment::Load") {"Setting type to default for \'#{args[0]}.\'"}
          end
          Material.new(args[0],DataFile::parsefunc(args[1],args[0]),args[2],args[4],args[5],type)
        end
      }  
    end
    
    def Map.GUILoad(lvl_name)
      File.delete("temp/map.obj") if File.file?("temp/map.obj")
      Zip::ZipFile.open(Object::Map::Root.gsub(/%current_level%/i,lvl_name)) { |zipfile|
        zipfile.extract("map.obj","temp/map.obj")
      }
      map=ObjectScript::ObjectClass.new("map")
      map.addStringProperty("name")
      map.addStringProperty("loadscreen_image",false,true)
      map.addStringProperty("file",false,true)
      map.addEnumProperty("allow_compile",["true","false"])
      map.addIntProperty("worldmap_id")
      map.addArrayProperty("node_size",2,2,:int)
      map.addEnumProperty("invert_colmap",["true","false"],false)
      maps=ObjectScript.new("temp/map.obj",map).run
      map=maps[0]
      if not File.file?(Object::Map::Root.gsub(/%current_level%/i,lvl_name)+".gfx")
        LoadGUI::makeImageFile(Object::Map::Root.gsub(/%current_level%/i,lvl_name)+".gfx", map)
      end
      File.delete("temp/map.obj")
      ls=LoadGUI::getLoadImage(lvl_name)
      ls.levelName=map["name"]
      FadeScreen.new(ls, 10).start
    end
    
    def Map.load(lvl_name)
      Dir.new("temp/").each { |file|
        File.delete("temp/"+file) if File.file?("temp/"+file)
      }
      
      Zip::ZipFile.open(Object::Map::Root.gsub(/%current_level%/i,lvl_name)) { |zipfile|
        zipfile.extract("init.rb","temp/initmap.rb")
        zipfile.extract("bump.bmp","temp/bump.bmp")
        zipfile.extract("bg.png","temp/mapbg.png")
        zipfile.extract("bumppager.def","temp/bump.def")
        zipfile.extract("map.obj","temp/map.obj")
        zipfile.extract("pathfinding.obj","temp/mappathfinding.obj")
      }
      
      map=ObjectScript::ObjectClass.new("map")
      map.addStringProperty("name")
      map.addStringProperty("loadscreen_image",false,true)
      map.addStringProperty("file",false,true)
      map.addEnumProperty("allow_compile",["true","false"])
      map.addIntProperty("worldmap_id")
      map.addArrayProperty("node_size",2,2,:int)
      map.addEnumProperty("invert_colmap",["true","false"],false)
      maps=ObjectScript.new("temp/map.obj",map).run
      map=maps[0]
      
=begin
      if not File.file?(Object::Map::Root.gsub(/%current_level%/i,lvl_name)+".gfx")
        LoadGUI::makeImageFile(Map::Root.gsub(/%current_level%/i,lvl_name)+".gfx", map)
      end
      ls=LoadGUI::getLoadImage(lvl_name)
=end
      
      if map.hasProperty?("file")
        Zip::ZipFile.open(Object::Map::Root.gsub(/%current_level%/i,lvl_name)) { |zipfile|
          map.eachof("file") { |file|
            zipfile.extract(file,"temp/"+file)
          }
        }
      end
  
      $window.background_image.draw(0, 0, ZOrder::Background)
      $window.map=Object::Map.new(map["name"], map["worldmap_id"], "temp/mapbg.png", "temp/bump.bmp", "temp/bump.def", map["node_size"][0], map["node_size"][1])
      $window.map.collisionMap.invert if map["invert_colmap"]=="true"
      
      link=ObjectScript::ObjectClass.new("link")
      link.addArrayProperty("clearance",2,2,:int)
      link.addArrayProperty("start",2,2,:int)
      link.addArrayProperty("step",3,3,:int,false,true)
      link.addArrayProperty("finish",2,2,:int)
      ignore=ObjectScript::ObjectClass.new("ignore")
      pathfinding=ObjectScript.new("temp/mappathfinding.obj",link,ignore).run
      
      if map["allow_compile"]=="true" and not File.file?(File.dirname(Object::Map::Root.gsub(/%current_level%/i,lvl_name))+"/map"+lvl_name+"pc.pcm")
        compile(File.dirname(Object::Map::Root.gsub(/%current_level%/i,lvl_name))+"/map"+lvl_name+"pc.pcm",lvl_name)
      end
=begin
    t=Thread.new {
      $framedrawn=false
      until $framedrawn
      end
      sleep(3)
    }
    t.join
=end
    
    #  ls.end
      RubyScript.new("temp/initmap.rb").run
     # RubyScript::ScriptUtillities::RunEvent("Map Init")
    end
   
    def Map.compile(outputfile, lvl_name)
      RubyScript.new("temp/initmap.rb").run #preliminary script run to ready map for saving process
      s=Save.new(outputfile, "MAP PRECOMPILED - "+lvl_name.upcase)
      s.addComponent("TileList","tiles.bin")
      s.addComponent("NodeMap","nodes.bin")
      s.addComponent("NodeMap","nodes.bin")
      s.addComponent("Player","player.bin")
      s.addComponent("NPCs","npcs.bin")
      #s.addComponent("CollisionMap","collision.bin") -ridiculously huge + slow to make file
      #s.addComponent("MapProperties","") -superflous
      s.write
    end
  end
  
  class Resources  
    def Resources.loadAnimations
      #animations
      DataFile.new(Animation::DefRoot).each(5) { |args| 
        if args!=false
          Animation.new(args[1], args[0], args[4].to_i, args[2].to_i,args[3].to_i, Boolean(args[5]))
        end
      }    
    end
    
    def Resources.loadCollisionMaps
      DataFile.new(AnimatedCollisionMap::DefRoot).each(5) { |args| 
        if args!=false
          AnimatedCollisionMap.new(args[1], args[0], args[4].to_i, args[2].to_i,args[3].to_i)
        end
      }   
    end
    
    def Resources.loadPlayers
      #players
      char=ObjectScript::ObjectClass.new("player")
      char.addStringProperty("name")
      char.addStringProperty("dispname")
      char.addStringProperty("animfile")
      char.addArrayProperty("tile", 3, 3, :int)
      char.addStringProperty("zkey", false)
      char.addStringProperty("xkey", false)
      char.addStringProperty("ckey", false)
      players=ObjectScript.new("data/characters/players/players.obj", char).run
      players.each { |char|
        $players[char["name"]]=char["animfile"]
        $players_data[char["name"]]=[char["dispname"],char["tile"][0].to_i,char["tile"][1].to_i,char["tile"][2].to_i]
        $players_defaults[char["name"]]=[ char["zkey"], char["xkey"], char["ckey"] ]
      }
    end
    
    def Resources.loadNPCs
      #NPCs
      char=ObjectScript::ObjectClass.new("npc")
      char.addStringProperty("name")
      char.addStringProperty("dispname")
      char.addStringProperty("animfile")
      char.addArrayProperty("tile", 3, 3, :int)
      chars=ObjectScript.new("data/characters/npcs/npcs.obj", char).run
      chars.each { |char|
        $npcs[char["name"]]=char["animfile"]
        $npcs_data[char["name"]]=[char["dispname"],char["tile"][0].to_i,char["tile"][1].to_i,char["tile"][2].to_i]
      }
    end
    
    def Resources.loadMaterials
      #RubyScript::Utils::RunEvent("Env Load")   
      #loadMapMaterialsOLD
      Map::loadMaterials
      loadItems
      loadAnimations
      loadCollisionMaps
      loadActions
      loadPlayers
      loadNPCs
    end
    
    def Resources.loadItems
      if File.file?("data/materials/items.rb")
        load "data/materials/items.rb"
        return
      end
      item=ObjectScript::ObjectClass.new("item")
      item.addStringProperty("name")
      item.addStringProperty("dispname")
      item.addStringProperty("icon")
      item.addStringProperty("script")
      ueqitem=ObjectScript::ObjectClass.new("stItem")
      ueqitem.addStringProperty("name")
      ueqitem.addStringProperty("dispname")
      ueqitem.addStringProperty("script")
      stitem=ObjectScript::ObjectClass.new("stItem")
      stitem.addStringProperty("name")
      stitem.addStringProperty("dispname")
      stitem.addStringProperty("icon")
      stitem.addStringProperty("script")
      suitem=ObjectScript::ObjectClass.new("suItem")
      suitem.addStringProperty("name")
      suitem.addStringProperty("dispname")
      suitem.addStringProperty("icon")
      suitem.addStringProperty("script")
      weapon=ObjectScript::ObjectClass.new("weapon")
      weapon.addStringProperty("name")
      weapon.addStringProperty("dispname")
      weapon.addStringProperty("icon")
      weapon.addStringProperty("action")
      armor=ObjectScript::ObjectClass.new("armor")
      armor.addStringProperty("name")
      armor.addStringProperty("dispname")
      armor.addStringProperty("icon")
      armor.addStringProperty("action")
      items=ObjectScript.new("data/materials/items.obj", item, stitem, suitem, weapon, armor).run
      f=File.new("data/materials/items.rb","w")
      estr=""
      items.each { |item|
        item["name"] = item["name"].capitalize
        basestr="def name\nreturn '#{item["name"]}'\nend\ndef dispName\nreturn '#{item["dispname"]}'\nend\ndef icon\nreturn '#{images["icon"]}'\nend"
        bsstr="def name\nreturn '#{item["name"]}'\nend\ndef dispName\nreturn '#{item["dispname"]}'\nend"
        case item.type
          when :item
            estr="class #{item["name"]} < Item\n"+basestr+"\ndef useScript\nreturn '#{+item["script"]}'\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :ueqItem
            estr="class #{item["name"]} < UnequipableItem\n"+bsstr+"\ndef useScript\nreturn '#{+item["script"]}'\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :stItem
            estr="class #{item["name"]} < StackableItem\n"+basestr+"\ndef useScript\nreturn '#{+item["script"]}'\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :suItem
            estr="class #{item["name"]} < SingleUseItem\n"+basestr+"\ndef useScript\nreturn '#{+item["script"]}'\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :weapon
            raise if Actions.getAction(item["action"])==nil
            estr="class #{item["name"]} < CombatItem\n"+basestr+"\ndef action\nreturn Action.getAction(#{item["action"]})\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :armor
            raise if Actions.getAction(item["action"])==nil
            estr="class #{item["name"]} < CombatItem\n"+basestr+"\ndef action\nreturn Action.getAction(#{item["action"]})\nend\nend"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
        end
      }
      f.close
    end
    
    def Resources.loadActions
      if File.file?("data/characters/actions/actions.rb")
        load "data/characters/actions/actions.rb"
        return
      end
      attack=ObjectScript::ObjectClass.new("attack")
      attack.addStringProperty("name")
      attack.addStringProperty("type")
    #  attack.addEnumProperty("damage_method", ["hp", "script", "kill"])
      attack.addIntProperty("damage")
      attack.addStringProperty("damage_script", false)
      attack.addEnumProperty("pushback", ["true", "false"])
      attack.addStringProperty("animfile")
      attack.addArrayProperty("property", 2, 2, :string, false, true)
      block=ObjectScript::ObjectClass.new("block")
      block.addStringProperty("name")
      block.addStringProperty("type")
      block.addStringProperty("block_script", false)
      attack.addStringProperty("animfile")
      attack.addArrayProperty("property", 2, 2, :string, false, true)
      action=ObjectScript::ObjectClass.new("action")
      action.addStringProperty("name")
      action.addStringProperty("type")
      #action.addStringProperty("script")
      attack.addArrayProperty("property", 2, 2, :string, false, true)
      items = ObjectScript.new("data/characters/actions/actions.obj", attack, block, action).run
      f=File.new("data/characters/actions/actions.rb","w")
      estr=""
      items.each { |item|
        type = item["type"].capitalize
        basestr="'#{item["name"]}', '#{item["animfile"]}'"
        properties = "{}"
        if item.hasProperty?("property")
          properties="{"
          item.eachof("property") { |data|
            properties+="'#{data[0]}'=>'#{data[1]}',"
          }
          properties.slice!(0,properties.size-1)
          properties+="}"
        end
        case item.type
          when :attack
            estr="#{type}.new("+basestr+", #{item["damage"]},"
            if item.hasProperty?("damage_script")
              estr+=" '#{item["damage_script"]}', " 
            else
              estr+=" false, "
            end
            estr+=item["pushback"].downcase+", "
            estr+=properties+")"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
          when :block
=begin
            animstr="Animation.new()"
            colmapstr="AnimatedCollisionMap.new('#{item["collision_map"][0]}',#{item["collision_map"][1]},#{item["collision_map"][2]},#{item["collision_map"][3]})"
            estr="#{item["type"]}.new("+basestr+", "+colmapstr+" , '#{+item["damage"]}',"
            if item.hasProperty?("damage_script")
              estr+=" '#{item["damage_script"]}', " 
            else
              estr+=" false, "
            end
            estr+=item["pushback"].downcase+","
            estr+=properties+")"
            f.write(estr)
            eval(estr, TOPLEVEL_BINDING)
=end
          when :action
            estr="#{type}.new("+basestr+", "+properties+")"
            eval(estr, TOPLEVEL_BINDING)
        end
      }
      f.close  
    end
  end
  
 # def make
 
  class LoadGUI
    def LoadGUI.getLoadImage(lvl_name)
      loadscreenimgs=Array.new
      f=File.new(Object::Map::Root.gsub(/%current_level%/i,lvl_name)+".gfx","r")
      f.each { |image|
        loadscreenimgs.push(image.strip)
      }
      f.close
      if loadscreenimgs[0]="DEFAULT"
        loadscreenimgs=Array.new
        Dir.new("img/banners/loadscreen/default").each { |image|
          loadscreenimgs.push(image) if File.file?("img/banners/loadscreen/default/"+image) 
        }
      end
      return LoadScreen.new(loadscreenimgs[rand(loadscreenimgs.size-1)], lvl_name)
=begin
      begin
        return $window.newImage(0,0,ZOrder::Top+1,loadscreenimgs[rand(loadscreenimgs.size-1)],true)
      rescue
        return $window.newImage(0,0,ZOrder::Top+1,"img/banners/loadscreen/default/"+loadscreenimgs[rand(loadscreenimgs.size-1)],true)
      end
=end
    end
    
    def LoadGUI.makeImageFile(file, map)
      f=File.new(file,"w")
      if map.hasProperty?("loadscreen_image")
        map.eachof("loadscreen_image") { |image|
          f.puts image
        }
      else
        f.puts "DEFAULT"
      end
      f.close
    end
  end
  
  def Environment.initializeWorld
    Resources::loadMaterials
  end
  
  def Environment.loadCampaign(file=nil)
    ZipFile.open("campaigns/default.dat") { |zipfile| #load default campaign/skin
      zipfile.foreach { |entry|
        zipfile.extract(entry,entry)
      }
    }
    f=File.new("currcmp.txt","w")
    f.write("DEFAULT")
    f.close
    if $skin!=nil
      ZipFile.open($skin) { |zipfile|  #load user chosen skin
        zipfile.foreach { |entry|
          zipfile.extract(entry,entry)
        }
      }
      f=File.new("currcmp.txt","w")
      f.write($skin+"\n")
      f.close
    end
    if file!=nil
      ZipFile.open(file) { |zipfile|  #load user chosen campaign
        zipfile.foreach { |entry|
          zipfile.extract(entry,entry)
        }
      }
      f=File.new("currcmp.txt","a")
      f.write(file)
      f.close
    end
  end
  
  def Environment.unloadCampaign(file)

  end
  
 # def draw
 #   
 # end
end